<!-- eslint-disable vue/multi-word-component-names -->
<template>
  <div class="webRTC-page">
    <div class="tips" @click="handleTest">{{ tips }}</div>
    <audio controls ref="audioRef" v-show="false" loop>
      <source src="@/assets/webRTC/alarm.mp3" type="audio/mpeg" />
    </audio>
    <div class="login-box" v-if="step === 0">
      <van-field label="自己的ID" v-model="clientId" placeholder="请输入用户ID"></van-field>
      <van-button type="primary" block @click="createWebSocket">登录</van-button>
    </div>
    <div class="login-box" v-if="step === 1">
      <div class="login-info">
        <div>登录成功</div>
        <div>当前的登录ID：{{ clientId }}</div>
      </div>
      <van-field label="呼叫的ID" v-model="userId" placeholder="请输入呼叫用户ID"></van-field>
      <div class="btn-group">
        <van-button type="success" block @click="handleCall(false)" class="mr-10"
          >呼叫语音</van-button
        >
        <van-button type="success" block @click="handleCall(true)">呼叫视频</van-button>
      </div>
    </div>
    <div class="local-video-box" v-if="step === 2">
      <video
        ref="localVideoRef"
        v-show="isCallVideo"
        :class="{ localVideo: !isCalling, remoteVideo: isCalling }"
        autoplay
        muted
      ></video>
      <video
        ref="remoteVideoRef"
        v-show="isCallVideo"
        :class="{ localVideo: isCalling, remoteVideo: !isCalling }"
        autoplay
        muted
      ></video>
      <div class="tisp" v-if="isCaller && !isCalling">等待对方接听...</div>
      <div class="tisp" v-if="isCalling">{{ showTime }}</div>
      <div class="btn-box">
        <img class="btn-img" src="@/assets/webRTC/guaduan.svg" @click="handleGua(false)" alt="" />
        <img
          class="btn-img"
          v-if="isShowJieting"
          src="@/assets/webRTC/jieting.svg"
          @click="handleGua(true)"
          alt=""
        />
        <img
          class="btn-img"
          v-if="isCalling && isCallVideo"
          src="@/assets/webRTC/changeVideo.svg"
          @click="handleChangeVideo"
          alt=""
        />
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { showToast } from 'vant'
import useWebsocketStore from '@/stores/modules/websocketStore'
const websocketStore = useWebsocketStore()

// 0: 登录 1: 呼叫 2: 呼叫中 3: 通话中
const step = ref(0)
const clientId = ref('')
const userId = ref('')
const isCaller = ref(true) // 呼叫者
const isShowJieting = ref(true) // 是否显示接听按钮
const tips = ref('') // 提示信息
const isCallVideo = ref(false) // 是否是视频通话
const isCalling = ref(false) // 是否在通话中
const callingTime = ref(0) // 通话时间
// 是否是前置摄像头
const isFrontCamera = ref(true)

const localVideoRef = ref<HTMLVideoElement>()
const remoteVideoRef = ref<HTMLVideoElement>()
const audioRef = ref<HTMLAudioElement>()
// 存储所有 PeerConnection
const peerConnections = {}
// 本地媒体流
let localStream

const showTime = computed(() => {
  const h = Math.floor(callingTime.value / 3600)
  const m = Math.floor((callingTime.value % 3600) / 60)
  const s = Math.floor((callingTime.value % 3600) % 60)
  return `${h < 10 ? '0' + h : h}:${m < 10 ? '0' + m : m}:${s < 10 ? '0' + s : s}`
})
let timer = null
watch(
  () => isCalling.value,
  (newVal) => {
    if (newVal) {
      timer = setInterval(() => {
        callingTime.value++
      }, 1000)
    } else {
      callingTime.value = 0
      clearInterval(timer)
    }
  }
)
function createWebSocket() {
  if (!clientId.value) {
    showToast('请输入用户ID')
    return
  }
  websocketStore.connection(clientId.value)
}
function handleCall(isVideo: boolean) {
  if (!userId.value) {
    showToast('请输入呼叫用户ID')
    return
  }
  if (userId.value === clientId.value) {
    showToast('不能呼叫自己')
    return
  }
  isCaller.value = true
  isCallVideo.value = isVideo
  isShowJieting.value = false
  step.value = 2
  startLocalStream().then((stream) => {
    websocketStore.sendMsg({
      type: 'call',
      isVideo,
      to: userId.value,
      from: clientId.value
    })
  })
}

async function handleCallanswer() {
  const pc1 = await createPeerConnection(userId.value)
  console.log('pc1', pc1)

  // // 创建 Offer
  pc1.createOffer().then((offer) => {
    pc1.setLocalDescription(offer)
    websocketStore.sendMsg({
      type: 'offer',
      sdp: offer.sdp,
      to: userId.value,
      aa: 'aa',
      from: clientId.value
    })
  })
}
async function handleTest() {
  //   const a = await navigator.mediaDevices.getUserMedia()
  console.log('获取本地媒体流', navigator.mediaDevices.getUserMedia({ audio: true, video: true }))
}
// 获取本地媒体流
async function startLocalStream() {
  try {
    // 确保 mediaDevices 存在
    if (!navigator.mediaDevices) {
      navigator.mediaDevices = {}
    }
    // 处理旧版浏览器前缀
    if (!navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices.getUserMedia =
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia ||
        navigator.getUserMedia
    }
    // facingMode user: 前置摄像头 environment: 后置摄像头
    if (localStream) {
      localStream.getTracks().forEach((track) => track.stop())
    }

    let mediaOptions
    if (isCallVideo.value) {
      mediaOptions = {
        video: {
          facingMode: isFrontCamera.value ? 'user' : 'environment'
        },
        audio: true
      }
    } else {
      mediaOptions = {
        audio: true,
        video: false
      }
    }

    const stream = await navigator.mediaDevices.getUserMedia(mediaOptions)
    console.log('stream', stream)
    localStream = stream
    localVideoRef.value!.srcObject = stream
    // localVideoRef.value!.play()

    return stream
  } catch (error) {
    console.error('Error accessing media devices:', error)
  }
}

// 切换摄像头
const handleChangeVideo = async () => {
  isFrontCamera.value = !isFrontCamera.value
  let stream = await startLocalStream()
  let peerConnection = peerConnections[userId.value]
  //   handleRemoteStream(stream, userId.value)

  const videoTrack = stream.getVideoTracks()[0]
  const audioTrack = stream.getAudioTracks()[0]
  // 更新视频轨道
  const videoSender = peerConnection.getSenders().find((s) => s.track.kind === 'video')
  if (videoSender) {
    videoSender.replaceTrack(videoTrack)
  }

  // 更新音频轨道
  const audioSender = peerConnection.getSenders().find((s) => s.track.kind === 'audio')
  if (audioSender) {
    audioSender.replaceTrack(audioTrack)
  }
}

// 处理远程流
function handleRemoteStream(stream, userId) {
  // 检查是否已经为该用户创建了 video 元素
  //   if (!remoteVideoElements[userId]) {
  //     const remoteVideo = document.createElement('video')
  //     remoteVideo.id = `remoteVideo-${userId}`
  //     remoteVideo.autoplay = true
  //     remoteVideos.appendChild(remoteVideo)
  //     remoteVideoElements[userId] = remoteVideo
  //   }

  //   // 设置视频源
  remoteVideoRef.value!.srcObject = stream
  remoteVideoRef.value!.muted = false
  isCalling.value = true
}
// 创建 PeerConnection
async function createPeerConnection(userId) {
  const pc = new RTCPeerConnection()
  peerConnections[userId] = pc

  // 添加本地流
  localStream.getTracks().forEach((track) => {
    pc.addTrack(track, localStream)
  })

  // 处理远程流
  pc.ontrack = (event) => {
    const stream = event.streams[0]
    console.log('收到远程流：', stream)

    handleRemoteStream(stream, userId)
  }

  // 处理 ICE Candidate
  pc.onicecandidate = (event) => {
    if (event.candidate) {
      websocketStore.sendMsg({
        type: 'ice',
        candidate: event.candidate,
        to: userId,
        from: clientId.value
      })
    }
  }

  return pc
}

// 处理 Offer
async function handleOffer(offer) {
  const pc = await createPeerConnection(offer.from)
  await pc.setRemoteDescription(offer)
  const answer = await pc.createAnswer()
  await pc.setLocalDescription(answer)
  websocketStore.sendMsg({ type: 'answer', sdp: answer.sdp, to: offer.from, from: offer.to })
}

// 处理 Answer
async function handleAnswer(answer) {
  const pc = peerConnections[answer.from]
  console.log('pc', pc, peerConnections, answer)
  await pc.setRemoteDescription(answer)
}

// 处理 ICE Candidate
async function handleICECandidate(candidate) {
  const pc = peerConnections[candidate.from]
  console.log('pc', pc, peerConnections, candidate)

  await pc.addIceCandidate(candidate.candidate)
}
async function handleGua(val: Boolean) {
  audioRef.value?.pause()
  if (val) {
    await startLocalStream()
    await createPeerConnection(userId.value)
    isShowJieting.value = false
  } else {
    closeVideo()
    step.value = 1
    isShowJieting.value = true
  }
  websocketStore.sendMsg({ type: 'call-answer', to: userId.value, from: clientId.value, val })
}
watch(
  () => websocketStore.msg,
  (messages) => {
    console.log('messages', messages)
    // 登录成功
    if (messages.type === 'login') {
      step.value = 1
    }
    // 收到呼叫
    if (messages.type === 'call') {
      userId.value = messages.from
      // 被呼叫
      isCaller.value = false
      isShowJieting.value = true
      isCallVideo.value = messages.isVideo
      step.value = 2
      audioRef.value?.play()
    }
    // 呼叫用户不在线
    if (messages.type === 'call-ack') {
      showToast(messages.msg)
      closeVideo()
      step.value = 1
    }
    // 收到呼叫回应
    if (messages.type === 'call-answer') {
      if (messages.val) {
        //同意
        userId.value = messages.from
        handleCallanswer()
      } else {
        //拒绝
        showToast('对方已挂断')
        closeVideo()
        step.value = 1
        isShowJieting.value = true
      }
    }
    // 收到offer
    if (messages.type === 'offer') {
      handleOffer(messages)
    } else if (messages.type === 'answer') {
      handleAnswer(messages)
    } else if (messages.type === 'ice') {
      handleICECandidate(messages)
    }
    // 有人离线
    if (messages.type === 'leave') {
      if (step.value === 2 && messages.from === userId.value) {
        showToast('对方已离线')
        closeVideo()
        step.value = 1
      }
    }
    // 弹出提示
    if (messages.type === 'tips') {
      showToast(messages.msg)
    }
    if (messages.type === 'wsClose') {
      tips.value = 'WebSocket连接已断开'
      step.value = 0
    }
    if (messages.type === 'wsOpen') {
      tips.value = ''
    }
  }
)

// 关闭视频通话
function closeVideo() {
  remoteVideoRef.value!.srcObject = null
  localVideoRef.value!.srcObject = null
  isCalling.value = false
  if (localStream) {
    localStream.getTracks().forEach((track) => track.stop())
    localStream = null
  }
}

onMounted(() => {
  //   websocketStore.connection(clientId.value)
})
</script>

<style scoped lang="less">
* {
  box-sizing: border-box;
}
.webRTC-page {
  width: 100%;
  height: 100%;
  padding: 20px;
  .tips {
    color: #f00;
    text-align: center;
    margin-bottom: 20px;
  }
  .login-box {
    // display: flex;
    // .el-input {
    //   width: 200px;
    // }
    .van-button {
      margin-top: 20px;
    }
    .login-info {
      text-align: center;
      margin-bottom: 20px;
      font-size: 13px;
    }
    .btn-group {
      display: flex;
    }
  }
  .local-video-box {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    .localVideo {
      width: 100%;
      height: 100%;
    }
    .remoteVideo {
      position: absolute;
      top: 0;
      right: 0;
      width: 200px;
      height: 300px;
    }
    .btn-box {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 7rem;
      display: flex;
      justify-content: space-around;
      .btn-img {
        width: 4rem;
      }
    }
    .tisp {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 12rem;
      text-align: center;
    }
  }
}
</style>
